package com.quad.innovators.salesease.service.impl.warehouse;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.quad.innovators.salesease.common.result.PageResultBean;
import com.quad.innovators.salesease.common.utils.SystemCodeUtils;
import com.quad.innovators.salesease.context.UserContext;
import com.quad.innovators.salesease.converter.SaleReturnOrderConverter;
import com.quad.innovators.salesease.enums.OrderStatusEnum;
import com.quad.innovators.salesease.enums.ProductActualStatusEnum;
import com.quad.innovators.salesease.enums.ResultCode;
import com.quad.innovators.salesease.enums.StatusEnum;
import com.quad.innovators.salesease.enums.SystemCodeEnum;
import com.quad.innovators.salesease.exception.BusinessException;
import com.quad.innovators.salesease.mapper.warehouse.SaleReturnOrderMapper;
import com.quad.innovators.salesease.model.common.Option;
import com.quad.innovators.salesease.model.dto.SysUserAuthInfo;
import com.quad.innovators.salesease.model.entity.base.Shop;
import com.quad.innovators.salesease.model.entity.stock.ProductInfoIdentity;
import com.quad.innovators.salesease.model.entity.warehouse.SaleReturnOrder;
import com.quad.innovators.salesease.model.form.warehouse.ReturnOrderDetailForm;
import com.quad.innovators.salesease.model.form.warehouse.SaleOrderDetailForm;
import com.quad.innovators.salesease.model.form.warehouse.SaleReturnOrderForm;
import com.quad.innovators.salesease.model.query.warehouse.SaleReturnOrderQuery;
import com.quad.innovators.salesease.model.vo.warehouse.SaleReturnOrderVO;
import com.quad.innovators.salesease.model.vo.warehouse.ScanCodeVO;
import com.quad.innovators.salesease.service.stock.ProductInfoIdentityService;
import com.quad.innovators.salesease.service.warehouse.ReturnOrderDetailService;
import com.quad.innovators.salesease.service.warehouse.ReturnOrderScanService;
import com.quad.innovators.salesease.service.warehouse.SaleOrderDetailService;
import com.quad.innovators.salesease.service.warehouse.SaleOrderScanService;
import com.quad.innovators.salesease.service.warehouse.SaleReturnOrderService;

import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;

/**
 * @author : shanshan.li
 * @createTime : 2024/12/18 16:00
 * @Version : 1.0 
 */
@Service
@RequiredArgsConstructor
public class SaleReturnOrderServiceImpl extends ServiceImpl<SaleReturnOrderMapper, SaleReturnOrder> implements SaleReturnOrderService {

    private final SaleReturnOrderConverter saleReturnOrderConverter;

    private final SaleOrderDetailService saleOrderDetailService;

    private final ReturnOrderDetailService returnOrderDetailService;

    private final SaleOrderScanService saleOrderScanService;

    private final ReturnOrderScanService returnOrderScanService;

    private final ProductInfoIdentityService productInfoIdentityService;

    @Override
    public PageResultBean<SaleReturnOrderVO> listPage(SaleReturnOrderQuery queryParams) {
        Page<SaleReturnOrderVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        Page<SaleReturnOrderVO> warehouseVOPage = this.baseMapper.listPage(page, queryParams);
        return saleReturnOrderConverter.toPageVo(warehouseVOPage);
    }

    @Override
    public SaleReturnOrderForm getFormData(String code) {
        SaleReturnOrder saleReturnOrder = this.baseMapper.selectOne(new QueryWrapper<SaleReturnOrder>().lambda().eq(SaleReturnOrder::getCode, code));
        if (ObjectUtils.isEmpty(saleReturnOrder)) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        SaleReturnOrderForm saleReturnOrderForm = saleReturnOrderConverter.toForm(saleReturnOrder);
        saleReturnOrderForm.setSaleOrderDetailFormList(saleOrderDetailService.getListBySaleReturnCode(code));
        saleReturnOrderForm.setReturnOrderDetailFormList(returnOrderDetailService.getListBySaleReturnCode(code));
        return saleReturnOrderForm;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(SaleReturnOrderForm form) {
        SaleReturnOrder entity = saleReturnOrderConverter.toEntity(form);
        LocalDate currentTime = LocalDate.now();
        String formatCurrent = currentTime.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        SaleReturnOrder saleReturnOrder = this.getOne(new QueryWrapper<SaleReturnOrder>()
                .lambda()
                .likeRight(SaleReturnOrder::getOrderNumber, formatCurrent)
                .orderByDesc(SaleReturnOrder::getOrderNumber)
                .last("limit 1"));
        if (ObjectUtils.isEmpty(saleReturnOrder)) {
            entity.setOrderNumber(formatCurrent + "00001");
        } else {
            entity.setOrderNumber(String.valueOf(Long.parseLong(saleReturnOrder.getOrderNumber()) + 1));
        }
        entity.setOrderStatus(OrderStatusEnum.EXIST.getCode());
        entity.setCode(SystemCodeUtils.getCode(SystemCodeEnum.SALE_RETURN_ORDER));
        return this.baseMapper.insert(entity) > 0
                && saleOrderDetailService.saveList(form.getSaleOrderDetailFormList(), entity.getCode())
                && returnOrderDetailService.saveList(form.getReturnOrderDetailFormList(), entity.getCode());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(String code, SaleReturnOrderForm form) {
        SaleReturnOrder saleReturnOrder = this.baseMapper.selectOne(new QueryWrapper<SaleReturnOrder>().lambda().eq(SaleReturnOrder::getCode, code));
        if (ObjectUtils.isEmpty(saleReturnOrder)) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        SaleReturnOrder entity = saleReturnOrderConverter.toEntity(form);
        entity.setId(saleReturnOrder.getId());
        return this.updateById(entity)
                && saleOrderDetailService.updateList(code, form.getSaleOrderDetailFormList())
                && returnOrderDetailService.updateList(code, form.getReturnOrderDetailFormList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(String code, Integer updateStatus) {
        SaleReturnOrder saleReturnOrder = this.baseMapper.selectOne(new QueryWrapper<SaleReturnOrder>().lambda().eq(SaleReturnOrder::getCode, code));
        if (ObjectUtils.isEmpty(saleReturnOrder)) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        if (!saleReturnOrder.getOrderStatus().equals(updateStatus - 1)) {
            return false;
        }
        saleReturnOrder.setOrderStatus(updateStatus);
        switch (OrderStatusEnum.useCodeGetEnum(updateStatus)){
            case READY:
                SysUserAuthInfo currentUser = UserContext.getCurrentUser();
                saleReturnOrder.setStockName(currentUser.getUsername());
                saleReturnOrder.setStockTime(LocalDateTime.now());
                break;
            case SIGNED:
                saleReturnOrder.setReceiveTime(LocalDateTime.now());
                List<ScanCodeVO> saleScanCodeList = saleOrderScanService.getScanDetailBySaleReturnCode(code);

                List<ScanCodeVO> returnScanCodeList = returnOrderScanService.getScanDetailBySaleReturnCode(code);
                Set<String> codeList = saleScanCodeList.stream().map(ScanCodeVO::getScanCode).collect(Collectors.toSet());
                Set<String> returnCodeList = returnScanCodeList.stream().map(ScanCodeVO::getScanCode).collect(Collectors.toSet());
                codeList.addAll(returnCodeList);

                // 查询出所有与当前订单相关的内容
                List<ProductInfoIdentity> productInfoIdentityList = productInfoIdentityService.list(new QueryWrapper<ProductInfoIdentity>().lambda().in(ProductInfoIdentity::getIdentityCode, codeList).or().in(ProductInfoIdentity::getPackingCode, codeList));
                productInfoIdentityList.forEach(model -> {
                    if (returnCodeList.contains(model.getIdentityCode()) || returnCodeList.contains(model.getPackingCode())) {
                        model.setActualStatus(ProductActualStatusEnum.IN_WAREHOUSE.getCode());
                        model.setActualLocationLastTime(LocalDate.now());
                        model.setActualLocationCode(saleReturnOrder.getWarehouseCode());
                        model.setActualLocationName(saleReturnOrder.getStockName());
                    } else if (codeList.contains(model.getIdentityCode()) || codeList.contains(model.getPackingCode())) {
                        model.setActualStatus(ProductActualStatusEnum.IN_SHOP.getCode());
                        model.setActualLocationLastTime(LocalDate.now());
                        model.setActualLocationCode(saleReturnOrder.getShopCode());
                        model.setActualLocationName(saleReturnOrder.getShopName());
                    }
                });
                return this.updateById(saleReturnOrder) && productInfoIdentityService.updateBatchById(productInfoIdentityList);
            case AUDIT:
                saleReturnOrder.setAuditTime(LocalDateTime.now());
                break;
            default:
                break;
        }
        return this.updateById(saleReturnOrder);
    }

    @Override
    public List<Option<String>> vehicleListOptions(String vehicleBringGoodsCode) {
        List<SaleReturnOrder> saleReturnOrderList = this.baseMapper.selectList(new LambdaQueryWrapper<SaleReturnOrder>().eq(SaleReturnOrder::getVehicleBringCode, "").or().eq(SaleReturnOrder::getVehicleBringCode, vehicleBringGoodsCode));
        return saleReturnOrderList.stream().map(it -> new Option<>(it.getCode(), it.getOrderNumber() + " " + it.getShopName())).collect(Collectors.toList());
    }

    @Override
    public List<String> getSaleReturnCodeList(String code) {
        List<SaleReturnOrder> saleReturnOrderList = this.baseMapper.selectList(new LambdaQueryWrapper<SaleReturnOrder>().eq(SaleReturnOrder::getVehicleBringCode, code)
                .and(model -> model.eq(SaleReturnOrder::getOrderStatus, OrderStatusEnum.EXIST).or().eq(SaleReturnOrder::getOrderStatus, OrderStatusEnum.READY.getCode())));
        return saleReturnOrderList.stream().map(SaleReturnOrder::getCode).toList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean bindSaleReturnOrder(String vehicleCode, List<String> saleReturnCodeList) {
        List<SaleReturnOrder> saleReturnOrderList = this.list(new QueryWrapper<SaleReturnOrder>().lambda().in(SaleReturnOrder::getCode, saleReturnCodeList));
        if (CollectionUtils.isNotEmpty(saleReturnOrderList)) {
            saleReturnOrderList.forEach(model -> {
                model.setVehicleBringCode(vehicleCode);
            });
            return this.updateBatchById(saleReturnOrderList);
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBindSaleReturnOrder(String vehicleCode, List<String> saleReturnCodeList) {
        Boolean updateVehicleIsNull = null;
        List<SaleReturnOrder> saleReturnOrderList = this.list(new QueryWrapper<SaleReturnOrder>().lambda().eq(SaleReturnOrder::getVehicleBringCode, vehicleCode));
        if (CollectionUtils.isNotEmpty(saleReturnOrderList)) {
            saleReturnOrderList.forEach(model -> {
                model.setVehicleBringCode("");
            });
            updateVehicleIsNull = this.updateBatchById(saleReturnOrderList);
        }
        return Boolean.TRUE.equals(updateVehicleIsNull) && bindSaleReturnOrder(vehicleCode, saleReturnCodeList);
    }

    @Override
    public List<String> getSaleScanCodeByVehicleCode(String vehicleCode) {
        return this.baseMapper.getSaleScanCodeByVehicleCode(vehicleCode);
    }

    @Override
    public List<String> getReturnScanCodeByVehicleCode(String vehicleCode) {
        return this.baseMapper.getReturnScanCodeByVehicleCode(vehicleCode);
    }
}
